package com.ctvit.cch.core.service.impl;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.ctvit.cch.core.mapper.HotRecordMapper;
import com.ctvit.cch.core.mapper.SocialPlatformMapper;
import com.ctvit.cch.core.pojo.config.HotRecordCollectorPlatformConfig;
import com.ctvit.cch.core.pojo.domain.HotRecord;
import com.ctvit.cch.core.pojo.domain.SocialPlatform;
import com.ctvit.cch.core.service.IHotRecordCollectorService;
import com.ctvit.cch.core.utils.AggregateScoreCalculatorUtils;
import com.ctvit.cch.core.utils.NumberConvertUtils;
import com.ruoyi.common.enums.HttpMethod;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.core.io.ClassPathResource;

import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Map;
import java.util.Objects;
import java.io.IOException;
import org.openqa.selenium.By;
import org.openqa.selenium.ElementClickInterceptedException;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.stereotype.Service;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 热点记录收集Service业务层处理
 * <p>
 * 该类负责实现热点数据收集相关的功能，包括不同平台的热榜数据收集和基于Selenium的网页数据收集
 *
 * @author heyingcheng
 * @date 2025/07/27
 */
@Slf4j
@Service
public class HotRecordCollectorServiceImpl implements IHotRecordCollectorService {

    private final SocialPlatformMapper socialPlatformMapper;

    private final HotRecordMapper hotRecordMapper;

    private final ThreadLocal<Map<String, SocialPlatform>> platformMap = new ThreadLocal<>() {
        @Override
        protected Map<String, SocialPlatform> initialValue() {
            return socialPlatformMapper.selectList(new LambdaQueryWrapper<SocialPlatform>()).stream()
                    .collect(Collectors.toMap(SocialPlatform::getPlatformId, Function.identity()));
        }
    };

    public HotRecordCollectorServiceImpl(SocialPlatformMapper socialPlatformMapper, HotRecordMapper hotRecordMapper) {
        this.socialPlatformMapper = socialPlatformMapper;
        this.hotRecordMapper = hotRecordMapper;
    }

    @Override
    public boolean collectHotRecords(String platformCode) {
        switch (platformCode) {
            case "DouYin":
                return collectDouYin();
            case "KuaiShou":
                return collectKuaiShou();
            case "BiLiBiLi":
                return collectBiLiBiLi();
            case "HaoKan":
                return collectHaoKan();
            case "YangShiPin":
                return collectYangShiPin();
            default:
                return false;
        }
    }

    private boolean collectByHttpRequest(HttpMethod httpMethod, String configFilePath,
            BiConsumer<HotRecordCollectorPlatformConfig, String> successPredicate) {
        InputStream inputStream = null;
        HttpResponse httpResponse = null;
        try {
            inputStream = new ClassPathResource(Objects.requireNonNull(configFilePath)).getInputStream();
            String configContent = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
            log.info("抖音热搜配置内容:[{}]", configContent);

            HotRecordCollectorPlatformConfig platformConfig = JSON.parseObject(configContent,
                    HotRecordCollectorPlatformConfig.class);

            // 构建HTTP请求
            HttpRequest httpRequest = switch (httpMethod) {
                case GET -> HttpRequest.get(Objects.requireNonNull(platformConfig.getUrl()));
                case POST -> HttpRequest.post(Objects.requireNonNull(platformConfig.getUrl()));
                default -> throw new IllegalArgumentException("不支持的HTTP方法: " + httpMethod);
            };

            if (MapUtils.isNotEmpty(platformConfig.getHeaders())) {
                // 添加所有请求头
                for (Map.Entry<String, String> entry : platformConfig.getHeaders().entrySet()) {
                    httpRequest.header(entry.getKey(), entry.getValue().toString());
                }
            }

            // 设置请求体
            if (StringUtils.isNotBlank(platformConfig.getRequestBody())) {
                httpRequest.body(platformConfig.getRequestBody());
            }

            // 设置超时时间
            httpRequest.timeout(ObjectUtils.defaultIfNull(platformConfig.getTimeout(), 30000));

            httpResponse = httpRequest.execute();
            int status = httpResponse.getStatus();
            String responseBody = httpResponse.body();

            log.info("请求[{}]热搜接口，状态码:[{}], 响应内容:[{}]", platformConfig.getPlatformCode(), status, responseBody);

            // 检查状态码是否为200
            if (status == 200) {
                successPredicate.accept(platformConfig, responseBody);
            }

            return status == 200;
        } catch (Exception e) {
            log.error("请求抖音热搜接口失败", e);
            return false;
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error("关闭配置文件输入流失败", e);
                }
            }

            if (httpResponse != null) {
                try {
                    httpResponse.close();
                } catch (Exception e) {
                    log.error("关闭响应体失败", e);
                }
            }
        }
    }

    @Override
    public boolean collectDouYin() {
        return collectByHttpRequest(HttpMethod.GET, "hot_record_collector_config_douyin.json",
                (platformConfig, responseBody) -> {
                    JSONObject bodyJsonObject = JSON.parseObject(responseBody);
                    if (NumberUtils.INTEGER_ZERO.equals(bodyJsonObject.getInteger("status_code"))) {
                        JSONArray wordJsonArray = (JSONArray) bodyJsonObject.getByPath("data.word_list");
                        for (int i = 0, size = wordJsonArray.size(); i < size; i++) {
                            JSONObject wordJsonObject = wordJsonArray.getJSONObject(i);
                            long score = wordJsonObject.getLongValue("hot_value");
                            if (score > 0) {
                                String keyword = wordJsonObject.getString("word");
                                Integer rank = wordJsonObject.getInteger("position");
                                Long eventTime = ObjectUtils.defaultIfNull(wordJsonObject.getLongValue("event_time"),
                                        System.currentTimeMillis() / 1000);
                                String linkFormat = platformConfig.getLinkFormat();
                                String link = String.format(Objects.requireNonNull(linkFormat),
                                        URLEncoder.encode(keyword, StandardCharsets.UTF_8));
                                String image = wordJsonObject.getByPath("word_cover.url_list[0]").toString();

                                assignHotRecord(Objects.requireNonNull(platformConfig.getPlatformId()), keyword,
                                        keyword, link, score, rank, eventTime, image,
                                        wordJsonObject.toString());
                            }
                        }
                    }
                });
    }

    @Override
    public boolean collectKuaiShou() {
        return collectByHttpRequest(HttpMethod.POST, "hot_record_collector_config_kuaishou.json",
                (platformConfig, responseBody) -> {
                    JSONObject bodyJsonObject = JSON.parseObject(responseBody);
                    JSONObject visionHotRank = bodyJsonObject.getJSONObject("data").getJSONObject("visionHotRank");

                    if (visionHotRank != null) {
                        JSONArray items = visionHotRank.getJSONArray("items");

                        for (int i = 0; i < items.size(); i++) {
                            JSONObject itemsJsonObject = items.getJSONObject(i);
                            long score = NumberConvertUtils.convertToLong(itemsJsonObject.getString("hotValue"));
                            if (score > 0) {
                                String keyword = itemsJsonObject.getString("name");
                                String link = String.format(Objects.requireNonNull(platformConfig.getLinkFormat()),
                                        URLEncoder.encode(keyword, StandardCharsets.UTF_8));
                                Integer rank = itemsJsonObject.getInteger("rank");
                                String image = itemsJsonObject.getString("poster");

                                assignHotRecord(Objects.requireNonNull(platformConfig.getPlatformId()), keyword,
                                        keyword, link, score, rank, System.currentTimeMillis() / 1000, image,
                                        itemsJsonObject.toString());
                            }
                        }
                    }
                });
    }

    @Override
    public boolean collectHaoKan() {
        return collectByHttpRequest(HttpMethod.GET, "hot_record_collector_config_haokan.json",
                (platformConfig, responseBody) -> {
                    JSONObject bodyJsonObject = JSON.parseObject(responseBody);
                    if (NumberUtils.INTEGER_ZERO.equals(bodyJsonObject.getInteger("errno"))) {
                        JSONArray wordJsonArray = (JSONArray) bodyJsonObject.getByPath("apiData.response.video");
                        for (int i = 0; i < wordJsonArray.size(); i++) {
                            JSONObject videoJsonObject = wordJsonArray.getJSONObject(i);
                            long score = NumberConvertUtils.convertToLong(videoJsonObject.getString("hot"));
                            if (score > 0) {
                                String keyword = videoJsonObject.getString("title");
                                String link = videoJsonObject.getString("pageUrl");
                                String image = videoJsonObject.getString("poster");
                                // 好看视频没有直接提供排名，使用索引+1作为排名
                                Integer rank = i + 1;

                                assignHotRecord(Objects.requireNonNull(platformConfig.getPlatformId()), keyword,
                                        keyword, link, score, rank, System.currentTimeMillis() / 1000, image,
                                        videoJsonObject.toString());
                            }
                        }
                    }
                });
    }

    @Override
    public boolean collectBiLiBiLi() {
        return collectByHttpRequest(HttpMethod.GET, "hot_record_collector_config_bilibili.json",
                (platformConfig, responseBody) -> {
                    // 解析响应体
                    JSONObject bodyJsonObject = JSON.parseObject(responseBody);
                    if (NumberUtils.INTEGER_ZERO.equals(bodyJsonObject.getInteger("code"))) {
                        JSONArray trendJsonArray = (JSONArray) bodyJsonObject.getByPath("data.trending.list");
                        for (int i = 0; i < trendJsonArray.size(); i++) {
                            JSONObject trendJsonObject = trendJsonArray.getJSONObject(i);
                            long score = NumberConvertUtils.convertToLong(trendJsonObject.getString("heat_score"));
                            if (score > 0) {
                                String keyword = trendJsonObject.getString("show_name");
                                Integer rank = i + 1;
                                String link = String.format(Objects.requireNonNull(platformConfig.getLinkFormat()),
                                        URLEncoder.encode(keyword, StandardCharsets.UTF_8));
                                String image = "";

                                assignHotRecord(Objects.requireNonNull(platformConfig.getPlatformId()), keyword,
                                        keyword, link, score, rank, System.currentTimeMillis() / 1000, image,
                                        trendJsonObject.toString());
                            }
                        }
                    }
                });
    }

    /**
     * 使用Selenium获取网页中的JSON数据
     * 
     * @param url 网页地址
     * @return 解析后的JSON对象
     */
    public boolean collectYangShiPin() {
        String url = "https://www.yangshipin.cn/";

        WebDriver driver = null;
        try {
            System.setProperty("webdriver.chrome.driver", "D:/BrowserDriver/chromedriver-137.0.7151.69.exe");
            ChromeOptions options = new ChromeOptions();
            // options.addArguments("--headless");
            options.addArguments("--no-sandbox");
            options.addArguments("--disable-dev-shm-usage");

            options.setExperimentalOption("useAutomationExtension", false);
            options.addArguments("--disable-blink-features=AutomationControlled");

            // 使用Selenium 4的新方式初始化ChromeDriver
            driver = new ChromeDriver(options);
            driver.get(url);

            try {
                // 等待页面加载完成
                WebDriverWait waitPage = new WebDriverWait(driver, Duration.ofSeconds(10));

                // 查找class为"winE-policy-close-b"的div元素
                WebElement closeButton = waitPage.until(
                        ExpectedConditions.elementToBeClickable(By.xpath("//div[@class='winE-policy-close-b']")));

                // 点击关闭按钮
                closeButton.click();
            } catch (Exception e) {
                log.error("关闭按钮点击异常", e);
            }

            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                log.warn("等待过程中被中断", e);
                Thread.currentThread().interrupt();
            }

            // 向下滑动2个屏幕高度
            JavascriptExecutor windowJs = (JavascriptExecutor) driver;
            windowJs.executeScript("window.scrollBy(0, window.innerHeight * 2);");

            List<WebElement> elements = driver.findElements(By.xpath("//div[@class='public']"));
            for (WebElement publicElement : elements) {
                try {
                    // 查找当前publicElement下class为comH-t-title的div元素
                    WebElement titleElement = publicElement.findElement(By.xpath(".//div[@class='comH-t-title']"));
                    // 获取该元素的文本内容并判断是否为"热门视频"
                    String innerText = titleElement.getText();
                    if ("热门视频".equals(innerText)) {
                        // 获取当前publicElement下class为"comH-item-a tobigBox"的div列表
                        List<WebElement> itemElements = publicElement
                                .findElements(By.xpath(".//div[@class='comH-item-a tobigBox']"));
                        int rank = 1;
                        for (WebElement itemElement : itemElements) {
                            try {
                                // 获取当前itemElement下class为"comH-item-a-fullTitle"的div的innerText
                                WebElement titleDiv = itemElement
                                        .findElement(By.xpath(".//div[@class='comH-item-a-fullTitle']"));
                                String keyword = titleDiv.getAttribute("innerText");

                                // 获取当前itemElement下的img标签
                                WebElement imgElement = itemElement
                                        .findElement(By.xpath(".//div[@class='comH-item-a-cover']/img"));
                                String image = imgElement.getAttribute("data-src");

                                log.info("标题:[{}], 图片地址:[{}]", keyword, image);

                                // 使用JavaScript点击元素，避免被遮挡
                                try {
                                    // 等待元素可点击
                                    WebDriverWait waitItem = new WebDriverWait(driver, Duration.ofSeconds(10));
                                    waitItem.until(ExpectedConditions.elementToBeClickable(itemElement));

                                    // 滚动元素到视图中心
                                    JavascriptExecutor itemJs = (JavascriptExecutor) driver;
                                    itemJs.executeScript(
                                            "arguments[0].scrollIntoView({block: 'center', behavior: 'smooth'});",
                                            itemElement);

                                    // 等待滚动完成
                                    Thread.sleep(500);

                                    // 尝试直接点击
                                    itemElement.click();
                                } catch (ElementClickInterceptedException e) {
                                    log.warn("直接点击被拦截，使用JavaScript执行点击");
                                    JavascriptExecutor executor = (JavascriptExecutor) driver;
                                    executor.executeScript("arguments[0].click();", itemElement);
                                } catch (Exception e) {
                                    log.error("点击元素时发生异常", e);
                                    // 即使点击失败也继续执行后续操作
                                }

                                // 等待新窗口出现
                                WebDriverWait waitItem = new WebDriverWait(driver, Duration.ofSeconds(10));
                                waitItem.until(ExpectedConditions.numberOfWindowsToBe(2));

                                // 获取所有窗口句柄
                                Set<String> windowHandles = driver.getWindowHandles();
                                Iterator<String> iterator = windowHandles.iterator();

                                // 获取原始窗口句柄
                                String originalWindow = iterator.next();
                                String newWindow = iterator.next();

                                // 切换到新标签页
                                driver.switchTo().window(newWindow);

                                // 获取新标签页的URL
                                String link = driver.getCurrentUrl();
                                log.info("新标签页地址:[{}]", link);

                                // 获取class="video-main-l-title"的div下的class="title overflow-1"的div的html
                                String summary = "";
                                try {
                                    WebElement videoMainTitle = driver
                                            .findElement(By.xpath("//div[@class='video-main-l-title']"));
                                    WebElement videoTitleElement = videoMainTitle
                                            .findElement(By.xpath(".//div[@class='title overflow-1']"));
                                    summary = videoTitleElement.getAttribute("innerHTML");
                                    log.info("标题VideoTitleHtml内容:[{}]", summary);
                                } catch (NoSuchElementException e) {
                                    log.warn("未找到指定的标题元素");
                                } catch (Exception e) {
                                    log.error("获取标题元素HTML时发生异常", e);
                                }

                                assignHotRecord("1954737312458473473", keyword, summary, link, 0, rank,
                                        System.currentTimeMillis() / 1000, image,
                                        new JSONObject().toString());

                                Thread.sleep(10000);

                                if (rank == 5) {
                                    try {
                                        // 查找并点击publicElement元素下class="comH-t-r-l-rimg ron"的div
                                        WebElement nextElement = publicElement
                                                .findElement(By.xpath(".//div[@class='comH-t-r-l-rimg ron']"));

                                        // 使用JavaScript点击避免被遮挡
                                        JavascriptExecutor executor = (JavascriptExecutor) driver;
                                        executor.executeScript(
                                                "arguments[0].scrollIntoView({block: 'center', behavior: 'smooth'});",
                                                nextElement);
                                        Thread.sleep(500);
                                        executor.executeScript("arguments[0].click();", nextElement);

                                        log.info("已点击下一页元素");
                                    } catch (NoSuchElementException e) {
                                        log.warn("未找到下一页元素");
                                    } catch (Exception e) {
                                        log.error("点击下一页元素时发生异常", e);
                                    }
                                }

                                rank++;
                                // 关闭新标签页并切换回原始页面
                                driver.close();
                                driver.switchTo().window(originalWindow);
                            } catch (Exception e) {
                                log.error("处理热门视频Item异常", e);
                            }
                        }

                        return true;
                    }
                } catch (NoSuchElementException e) {
                    // 元素不存在，跳过当前循环
                    log.error("元素不存在, innerHTML:[{}]", publicElement.getAttribute("innerHTML"), e);
                }
            }
            return true;
        } catch (Exception e) {
            log.error("使用Selenium提取页面数据失败，URL:[{}]", url, e);
            return false;
        } finally {
            if (driver != null) {
                try {
                    driver.quit();
                } catch (Exception e) {
                    log.error("关闭WebDriver失败", e);
                }
            }
        }
    }

    /**
     * 赋值热榜记录
     *
     * @param platformId 平台ID
     * @param title      标题
     * @param summary    摘要
     * @param link       链接
     * @param score      分数
     * @param rank       排名
     * @param image      图片URL
     * @param rawContent 原始内容
     */
    private void assignHotRecord(String platformId, String title, String summary, String link, long score, Integer rank,
            Long eventTime,
            String image, String rawContent) {
        HotRecord hotRecord = new HotRecord();
        hotRecord.setRecordId(IdWorker.getIdStr());
        hotRecord.setPlatformId(platformId);
        hotRecord.setKeyword(title);
        hotRecord.setTitle(title);
        hotRecord.setSummary(summary);
        hotRecord.setLink(link);
        hotRecord.setScore(score);
        hotRecord.setRank(rank);
        hotRecord.setEventTime(eventTime);
        hotRecord.setRawImage(image);
        hotRecord.setRawContent(rawContent);
        hotRecord.setStatus(NumberUtils.INTEGER_MINUS_ONE.toString());
        hotRecord.setCreateBy("admin");
        hotRecord.setCreateTime(LocalDateTime.now());
        hotRecord.setUpdateBy("admin");
        hotRecord.setUpdateTime(LocalDateTime.now());
        insertOrUpdate(hotRecord);
    }

    /**
     * 插入或更新热榜记录
     *
     * @param hotRecord 热榜记录
     */
    private void insertOrUpdate(HotRecord hotRecord) {
        LambdaQueryWrapper<HotRecord> qWrapper = new LambdaQueryWrapper<HotRecord>()
                .eq(HotRecord::getKeyword, hotRecord.getKeyword())
                .eq(HotRecord::getPlatformId, hotRecord.getPlatformId());
        HotRecord dbOne = hotRecordMapper.selectOne(qWrapper);
        if (dbOne == null) {
            hotRecordMapper.insert(hotRecord);
        } else {
            SocialPlatform platform = Objects.requireNonNull(platformMap.get()).get(hotRecord.getPlatformId());

            LambdaUpdateWrapper<HotRecord> uWrapper = new LambdaUpdateWrapper<HotRecord>();
            uWrapper.eq(HotRecord::getRecordId, dbOne.getRecordId());
            uWrapper.set(HotRecord::getScore, hotRecord.getScore());
            uWrapper.set(HotRecord::getRank, hotRecord.getRank());
            if (NumberUtils.INTEGER_ZERO.toString().equals(dbOne.getStatus())) {
                uWrapper.set(HotRecord::getAggregateScore, BigDecimal.valueOf(AggregateScoreCalculatorUtils
                        .calculateAggregateScore(
                                platform.getPlatformWeight(), platform.getMaxRawScore(),
                                hotRecord.getScore(), hotRecord.getRank(),
                                dbOne.getUpdateTime(),
                                dbOne.getSpreadWide(), dbOne.getInfluenceDepth(), dbOne.getCreativeValue())));
            }
            uWrapper.set(HotRecord::getUpdateBy, hotRecord.getUpdateBy());
            uWrapper.set(HotRecord::getUpdateTime, hotRecord.getUpdateTime());
            hotRecordMapper.update(uWrapper);
        }
    }

}